package com.hyt.it.ogt.ks.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hyt.it.ogt.eventhandler.enums.ActionTypeEnum;
import com.hyt.it.ogt.eventhandler.service.ICandidateStateChangeService;
import com.hyt.it.ogt.eventhandler.service.ICandidateWarnService;
import com.hyt.it.ogt.ks.enums.ApplyCheckSkipTypeCode;
import com.hyt.it.ogt.ks.enums.CandidateStatusCode;
import com.hyt.it.ogt.ks.enums.PaperItemTypeCode;
import com.hyt.it.ogt.ks.enums.log.*;
import com.hyt.it.ogt.ks.model.entity.ApplyCheck;
import com.hyt.it.ogt.ks.model.entity.CandidateLog;
import com.hyt.it.ogt.ks.model.entity.CandidateLogOther;
import com.hyt.it.ogt.ks.model.entity.CandidatePaper;
import com.hyt.it.ogt.ks.model.vo.LogVO;
import com.hyt.it.ogt.ks.model.vo.log.*;
import com.hyt.it.ogt.ks.service.ILogService;
import com.hyt.it.ogt.ks.util.DateUtil;
import com.hyt.it.ogt.opertaion.track.model.AnswerLogVO;
import com.hyt.it.ogt.opertaion.track.model.KsWarningLogVO;
import com.hyt.it.ogt.opertaion.track.model.OtherLogVO;
import com.hyt.it.ogt.opertaion.track.service.IOperationTrackService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
@Slf4j
public class LogServiceImpl implements ILogService {
    @Resource
    private IOperationTrackService iOperationTrackService;
    @Resource
    private ICandidateWarnService iCandidateWarnService;
    @Resource
    private ICandidateStateChangeService iCandidateStateChangeService;

    @Override
    public void saveAnswerLog(List<CandidateLog> data) {
        List<AnswerLogVO> list = new ArrayList<>();
        log.debug("# 保存答案轨迹数据111:{}", JSON.toJSONString(data));
        for (CandidateLog item : data) {
            AnswerLogVO log = AnswerLogVO.builder().examId(item.getExamId()).candidateId(item.getCandidateId())
                    .beginTime(DateUtil.date2String(item.getBeginTime())).eventType(item.getEventType())
                    .operateType(item.getOperateType()).itemId(item.getItemId())
                    .itemTypeName(item.getItemType())
                    .operateContent(JSON.toJSONString(AnswerVO.builder().takeTime(item.getTakeTime())
                            .answer(this.answerChange(item.getItemType(), item.getOperateContent())).build()))
                    .build();
            // 在此deque的尾部插入指定的元素
            list.add(log);
        }
        log.debug("# 保存答案轨迹数据222:{}", JSON.toJSONString(list));
        iOperationTrackService.answerTrackLogSave(list);
    }

    @Override
    public void saveAnswerLog(CandidateLog item) {
            AnswerLogVO log = AnswerLogVO.builder().examId(item.getExamId()).candidateId(item.getCandidateId())
                    .beginTime(DateUtil.date2String(item.getBeginTime())).eventType(item.getEventType())
                    .operateType(item.getOperateType()).itemId(item.getItemId())
                    .itemTypeName(item.getItemType())
                    .operateContent(JSON.toJSONString(AnswerVO.builder().takeTime(item.getTakeTime())
                            .answer(this.answerChange(item.getItemType(), item.getOperateContent())).build()))
                    .build();
        iOperationTrackService.answerTrackLogSave(log);
    }

    private String answerChange(String itemType, String answer) {
        if(Objects.equals(itemType, PaperItemTypeCode.ITEM_TYPE_JUDGMENT_CODE.getCode())) {
            if(Objects.equals("0", answer)) {
                return "错";
            } else if(Objects.equals("1", answer)) {
                return "对";
            } else {
                return answer;
            }
        } else {
            return answer;
        }
    }

    @Override
    public void loginLog(String examId, String candidateId, boolean secondLogin, String from, String deviceType, String ip) {

        String now = DateUtil.getNowStr();
        if ("2".equals(from)) {
            iOperationTrackService.otherTrackLogSave(
                    AnswerLogVO.builder().examId(examId).candidateId(candidateId)
                            .eventType(LogEventType.OPERATOR_LOG.getCode()).beginTime(now)
                            .operateContent(JSON.toJSONString(LogCandidateLoginVO.builder().ip(ip)
                                    .client(deviceType).build()))
                            .operateType(CandidateOperatorLogType.SELECT_EXAM.getCode()).build());
        } else {
            if (secondLogin) {
                // 二次登录需要增加预警记录
                iOperationTrackService.otherTrackLogSave(
                        AnswerLogVO.builder().examId(examId).candidateId(candidateId)
                                .eventType(LogEventType.ALERT_LOG.getCode()).beginTime(now)
                                .operateContent(JSON.toJSONString(LogCandidateLoginVO.builder().ip(ip)
                                        .client(deviceType).build()))
                                .operateType(CandidateWarnLogType.LOGIN_SECOND_TIME.getCode()).build());
                iOperationTrackService.ksWarningSave(KsWarningLogVO.builder()
                        .examId(examId).candidateId(candidateId)
                        .warnType(CandidateWarnLogType.LOGIN_SECOND_TIME.getCode()).createDate(now).build());
                iCandidateWarnService.addCandidateWarn(examId, candidateId);
            } else {
                // 首次登录轨迹
                iOperationTrackService.otherTrackLogSave(
                        AnswerLogVO.builder().examId(examId).candidateId(candidateId)
                                .eventType(LogEventType.OPERATOR_LOG.getCode())
                                .operateContent(JSON.toJSONString(LogCandidateLoginVO.builder().ip(ip)
                                        .client(deviceType).build()))
                                .beginTime(now).operateType(CandidateOperatorLogType.LOG_IN.getCode()).build());
            }
        }

        iCandidateStateChangeService.candidateStateChange(examId, candidateId,
                ActionTypeEnum.CANDIDATE_STATE.getTypeCode(), CandidateStatusCode.LOGIN.getCode());

        //iMonitorStatisticsSubmitService.addNum(examId, MonitorStatisticsTypeCode.LOGIN_NUM.getCode(), candidateId, false, 1);
    }

    @Override
    public void finishExamLog(String examId, String candidateId, String paperId, String paperVersion, Integer finishType) {
        // 保存轨迹
        iOperationTrackService.answerTrackLogSave(
                AnswerLogVO.builder().examId(examId).candidateId(candidateId)
                        .eventType(LogEventType.ANSWER_LOG.getCode())
                        .operateType(CandidateAnswerLogType.FINISH.getCode())
                        .operateContent(JSON.toJSONString(LogFinishExamVO.builder().paperId(paperId)
                                .paperVersion(paperVersion).finishType(finishType).build()
                        ))
                        .beginTime(DateUtil.getNowStr()).build()
        );
        /*iMonitorStatisticsSubmitService.addNum(examId, MonitorStatisticsTypeCode.SUBMIT_PAPER_NUM.getCode(),
                candidateId, false, 1);*/
    }

    @Override
    public void markItem(String examId, String candidateId, String itemId) {
        iOperationTrackService.answerTrackLogSave(AnswerLogVO.builder()
                .examId(examId).candidateId(candidateId)
                .eventType(LogEventType.ANSWER_LOG.getCode()).itemId(itemId)
                .operateType(CandidateAnswerLogType.MARK.getCode())
                .beginTime(DateUtil.getNowStr()).build());
    }

    @Override
    public void sureInfoLog(String examId, String candidateId) {
        iOperationTrackService.otherTrackLogSave(OtherLogVO.builder().examId(examId)
                .candidateId(candidateId).eventType(LogEventType.OPERATOR_LOG.getCode())
                .operateType(CandidateOperatorLogType.SURE_INFO.getCode()).beginTime(DateUtil.getNowStr()).build());
    }

    @Override
    public void startExamLog(String examId, String candidateId) {
        iOperationTrackService.otherTrackLogSave(OtherLogVO.builder().examId(examId)
                .candidateId(candidateId).eventType(LogEventType.OPERATOR_LOG.getCode())
                .operateType(CandidateOperatorLogType.IN_ANSWER.getCode()).beginTime(DateUtil.getNowStr()).build());
        /*iMonitorStatisticsSubmitService.addNum(examId, MonitorStatisticsTypeCode.EXAM_CANDIDATE_TAKE_NUM.getCode(),
                candidateId, false, 1);*/
    }

    @Override
    public void recoverExamLog(String examId, String candidateId, String userId, String paperId, String paperVersion) {
        List<OtherLogVO> logVOList = new ArrayList<>();
        logVOList.add(OtherLogVO.builder().examId(examId)
                        .candidateId(candidateId).eventType(LogEventType.EXAMINATION_LOG.getCode())
                        .operateType(AdminOperatorLogType.CANCEL_SUBMIT.getCode()).beginTime(DateUtil.getNowStr())
                        .operateUser(userId).operateContent(
                                JSON.toJSONString(CancelSubmitPaperLogVO.builder().paperId(paperId)
                                        .paperVersion(paperVersion).build())).build());
        iOperationTrackService.otherTrackLogSave(logVOList);
    }

    @Override
    public void addTimeLog(String examId, String candidateId, String paperId, String paperVersion,
                           Long extraTime, String userId, LocalDateTime now) {
        iOperationTrackService.otherTrackLogSave(OtherLogVO.builder().examId(examId)
                .candidateId(candidateId).operateType(AdminOperatorLogType.ADD_SUB_TIME.getCode())
                .eventType(LogEventType.EXAMINATION_LOG.getCode())
                .operateContent(JSON.toJSONString(LogAddTimeVO.builder().timeLength(extraTime)
                        .paperId(paperId).paperVersion(paperVersion).build()))
                .operateUser(userId).beginTime(DateUtil.date2String(LocalDateTime.now())).build());
    }

    @Override
    public void resetLoginLog(String examId, String candidateId, String userId) {
        iOperationTrackService.otherTrackLogSave(OtherLogVO.builder().examId(examId).candidateId(candidateId)
                .eventType(LogEventType.EXAMINATION_LOG.getCode()).beginTime(DateUtil.getNowStr())
                .operateType(AdminOperatorLogType.RESEAT_LOGIN_TIME.getCode()).operateUser(userId).build());
    }

    @Override
    public void applySkipLog(ApplyCheck applyCheck, ApplyCheckSkipTypeCode type, LocalDateTime createDate) {
        OtherLogVO otherLogVO = OtherLogVO.builder().examId(applyCheck.getExamId()).candidateId(applyCheck.getCandidateId())
                .beginTime(DateUtil.date2String(createDate)).build();
        switch (type) {
            case DEVICE_CHECK:
                otherLogVO.setEventType(LogEventType.OPERATOR_LOG.getCode());
                otherLogVO.setOperateType(CandidateOperatorLogType.DEVICE_CHECK_SKIP_APPLY.getCode());
                otherLogVO.setOperateContent(applyCheck.getOperateContent());
                break;
            case ID_FACE:
                otherLogVO.setEventType(LogEventType.OPERATOR_LOG.getCode());
                otherLogVO.setOperateType(CandidateOperatorLogType.ID_FACE_SKIP_APPLY.getCode());
                break;
            case MANUAL_REVIEW_FACE_APPLY:
                otherLogVO.setEventType(LogEventType.OPERATOR_LOG.getCode());
                otherLogVO.setOperateType(CandidateOperatorLogType.ID_FACE_SKIP_APPLY.getCode());
                break;
            default:
                break;
        }
        iOperationTrackService.otherTrackLogSave(otherLogVO);
    }

    @Override
    public void screenShotLog(String examId, String id) {
        /*iOperationTrackService.ksWarningSave(KsWarningLogVO.builder()
                .examId(examId).candidateId(id)
                .warnType(CandidateWarnLogType.CUT_SCREEN.getCode())
                .createDate(DateUtil.getNowStr()).build());*/
    }

    @Override
    public void faceLog(String examId, String examCandidateId, String orderId) {
        iOperationTrackService.otherTrackLogSave(OtherLogVO.builder()
                .examId(examId).candidateId(examCandidateId).beginTime(DateUtil.getNowStr())
                .eventType(LogEventType.OPERATOR_LOG.getCode())
                .operateType(CandidateOperatorLogType.ID_CHECK.getCode())
                .operateContent(JSON.toJSONString(FaceOrderVo.builder().orderId(orderId).build()))
                .build());
    }

    @Override
    public void faceFailLog(String examId, String examCandidateId) {
        iOperationTrackService.otherTrackLogSave(OtherLogVO.builder()
                .examId(examId).candidateId(examCandidateId).beginTime(DateUtil.getNowStr())
                .eventType(LogEventType.ALERT_LOG.getCode())
                .operateType(CandidateWarnLogType.FACE_ERROR.getCode()).build());

        iOperationTrackService.ksWarningSave(KsWarningLogVO.builder()
                .examId(examId).candidateId(examCandidateId)
                .warnType(CandidateWarnLogType.FACE_ERROR.getCode())
                .createDate(DateUtil.getNowStr()).build());

        iCandidateWarnService.addCandidateWarn(examId, examCandidateId);
    }

    @Override
    public void applyCheckLog(ApplyCheck dbApplyCheck) {
        log.info("审核结果进入异常管理：{}", dbApplyCheck);
        iOperationTrackService.otherTrackLogSave(OtherLogVO.builder()
                .examId(dbApplyCheck.getExamId())
                .candidateId(dbApplyCheck.getCandidateId())
                .eventType(LogEventType.EXAMINATION_LOG.getCode())
                .operateType(convertCandidateOpType(dbApplyCheck.getOperateType()))
                .operateContent(JSON.toJSONString(new CandidateLogOther.OperateContent().setApplyResult(dbApplyCheck.getState())))
                .beginTime(DateUtil.date2String(dbApplyCheck.getUpdateDate()))
                .operateUser(dbApplyCheck.getOperateUser())
                .build());
    }

    private Integer convertCandidateOpType(Integer operateType) {
        if (Objects.equals(CandidateOperatorLogType.DEVICE_CHECK_SKIP_APPLY.getCode(), operateType)) {
            return AdminOperatorLogType.DEVICE_CHECK_PASSED.getCode();
        } else if (Objects.equals(CandidateOperatorLogType.ID_FACE_SKIP_APPLY.getCode(), operateType)) {
            return AdminOperatorLogType.ID_CHECK_PASSED.getCode();
        }
        return null;
    }

    @Override
    public void cancelPackageCommitLog(CandidatePaper candidatePaper, String userId) {
        iOperationTrackService.otherTrackLogSave(OtherLogVO.builder().examId(candidatePaper.getExamId())
                .candidateId(candidatePaper.getCandidateId()).eventType(LogEventType.EXAMINATION_LOG.getCode())
                .operateType(AdminOperatorLogType.CANCEL_SUBMIT.getCode()).beginTime(DateUtil.getNowStr())
                .operateUser(userId).operateContent(
                        JSON.toJSONString(CancelSubmitPaperLogVO.builder().paperId(candidatePaper.getPaperId())
                                .paperVersion(candidatePaper.getPaperVersion()).build())).build());
    }

    @Override
    public void promiseLog(LogVO logVO) {
        iOperationTrackService.otherTrackLogSave(OtherLogVO.builder().examId(logVO.getExamId()).candidateId(logVO.getCandidateId())
                .beginTime(DateUtil.getNowStr()).eventType(LogEventType.OPERATOR_LOG.getCode())
                .operateType(CandidateOperatorLogType.CANDIDATE_MAKE_BELIEVE.getCode()).build());
    }

    @Override
    public String getIp(HttpServletRequest request) {
        if (request == null) {
            return "";
        }
        String ip = request.getRemoteAddr();
        String headerIP = request.getHeader("x-real-ip");
        if (headerIP == null || "".equals(headerIP) || "null".equals(headerIP)) {
            headerIP = request.getHeader("x-forwarded-for");
        }
        //System.out.println(“headerIP:”+headerIP);
        if (headerIP != null && !"".equals(headerIP) && !"null".equals(headerIP)) {
            ip = headerIP;
        }
        return ip;
    }

    @Override
    public void appLog(CandidateLogOther candidateLog) {
        iOperationTrackService.otherTrackLogSave(OtherLogVO.builder()
                .examId(candidateLog.getExamId()).candidateId(candidateLog.getCandidateId()).beginTime(DateUtil.getNowStr())
                .eventType(LogEventType.ALERT_LOG.getCode())
                .operateType(candidateLog.getOperateType())
                .operateContent(candidateLog.getOperateContent()).build());
    }
}
